package org.gongliang.jfinal.utils;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Enumeration;

import gnu.io.CommPort;
import gnu.io.CommPortIdentifier;
import gnu.io.NoSuchPortException;
import gnu.io.PortInUseException;
import gnu.io.SerialPort;
import gnu.io.UnsupportedCommOperationException;

public class IOTest {
	
	private static Integer timeCheckSum;
	
	
	   public Integer getTimeCheckSum() {
		return timeCheckSum;
	}

	public void setTimeCheckSum(Integer timeCheckSum) {
		this.timeCheckSum = timeCheckSum;
	}

	/*类方法 不可改变 不接受继承
     * 扫描获取可用的串口
     * 将可用串口添加至list并保存至list
     */
    public static final ArrayList<String> uartPortUseAblefind()
    {
        //获取当前所有可用串口 
        //由CommPortIdentifier类提供方法
        Enumeration<CommPortIdentifier> portList=CommPortIdentifier.getPortIdentifiers();
        ArrayList<String> portNameList=new ArrayList();
        //添加并返回ArrayList
        while(portList.hasMoreElements())
        {
            String portName=portList.nextElement().getName();
            portNameList.add(portName); 
        }
        return portNameList;
    }
    
    /*
     * 串口常见设置
     * 1)打开串口
     * 2)设置波特率 根据单板机的需求可以设置为57600 ...
     * 3)判断端口设备是否为串口设备
     * 4)端口是否占用
     * 5)对以上条件进行check以后返回一个串口设置对象new UARTParameterSetup()
     * 6)return:返回一个SerialPort一个实例对象，若判定该com口是串口则进行参数配置
     *   若不是则返回SerialPort对象为null
     */
    public static final SerialPort portParameterOpen(String portName,int baudrate)
    {
        SerialPort serialPort=null;
        try 
        {  //通过端口名识别串口
           CommPortIdentifier portIdentifier = CommPortIdentifier.getPortIdentifier(portName);
           //打开端口并设置端口名字 serialPort和超时时间 2000ms
           CommPort commPort=portIdentifier.open(portName,1000);
           //进一步判断comm端口是否是串口 instanceof
           if(commPort instanceof SerialPort)
           {
               System.out.println("该COM端口是串口！");
               //进一步强制类型转换
               serialPort=(SerialPort)commPort;
               //设置baudrate 此处需要注意:波特率只能允许是int型 对于57600足够
               //8位数据位
               //1位停止位
               //无奇偶校验
               serialPort.setSerialPortParams(baudrate, SerialPort.DATABITS_8,SerialPort.STOPBITS_1, SerialPort.PARITY_NONE);
               //串口配制完成 log
               System.out.println("串口参数设置已完成，波特率为"+baudrate+",数据位8bits,停止位1位,无奇偶校验");
           }
           //不是串口
           else
           {
               System.out.println("该com端口不是串口,请检查设备!");
               //将com端口设置为null 默认是null不需要操作
           }

        } 
        catch (NoSuchPortException e) 
        {
            e.printStackTrace();
        } 
        catch (PortInUseException e) 
        {
            e.printStackTrace();
        } 
        catch (UnsupportedCommOperationException e)
        {
            e.printStackTrace();
        }

        return serialPort;      
    }
    
    /*
     * 上位机往单板机通过串口发送数据
     * 串口对象 seriesPort 
     * 数据帧:dataPackage
     * 发送的标志:数据未发送成功抛出一个异常
     */
    public static void uartSendDatatoSerialPort(SerialPort serialPort,byte[] dataPackage)
    {
        OutputStream out=null;
        try
        {
            out=serialPort.getOutputStream();
            out.write(dataPackage);
            out.flush();
        } catch (IOException e) 
        {
            e.printStackTrace();
        }finally
        {
            //关闭输出流
            if(out!=null)
            {
                try 
                {
                    out.close();
                    out=null;
                    System.out.println("数据已发送完毕!");
                } catch (IOException e) 
                {
                    e.printStackTrace();
                }   
            }
        }           
     }
    
    /*
     * 上位机接收数据
     * 串口对象seriesPort
     * 接收数据buffer
     * 返回一个byte数组
     */
    public  static  byte[] uartReceiveDatafromSingleChipMachine(SerialPort serialPort)
    {
        byte[] receiveDataPackage=null;
        InputStream in=null;
        try 
        {
            in=serialPort.getInputStream();
            //获取data buffer数据长度
            int bufferLength=in.available();
            while(bufferLength!=0)
            {
                receiveDataPackage=new byte[bufferLength];
                in.read(receiveDataPackage);
                bufferLength=in.available();

            }
        } 
        catch (IOException e) 
        {
            e.printStackTrace();
        }
        return receiveDataPackage;
    }   
    
    public static String getCurrentDateTime()
    {
        //单例模式
         Calendar calendar=Calendar.getInstance();
         int year = calendar.get(Calendar.YEAR);//获取年份  
         int month=calendar.get(Calendar.MONTH);//获取月份   
         int day=calendar.get(Calendar.DATE);//获取日期  
         int minute=calendar.get(Calendar.MINUTE);//分   
         int hour=calendar.get(Calendar.HOUR);//小时   
         int second=calendar.get(Calendar.SECOND);//秒  
         String curerentDateTime = year + " " + (month + 1 )+ " " + day + " "+ (hour+12) + " " + minute + " " + second + " ";
         timeCheckSum=year+(month+1)+day+(hour+12)+minute+second;
         return curerentDateTime;  
    }
    
    /*
     * 将以上时间字符串进行隔开用byte[]保存
     */
    public static byte[] dateTimeBytesGet(String currenDateTime)
    {
        //对当前时间参数进行格式判断
        //对格式进行判断
        int rawDataSize=6;
        byte[] dateTimeBytes=new byte[rawDataSize+1];
        String[] currentDateTimeSplit=currenDateTime.split(" ");
        if(currentDateTimeSplit.length==rawDataSize)
        {
            //时间数据格式正确
            //eg 2016 12 23 22 18 26
            //使用byte[]进行存储时需要 -128~+127
            //对于年份使用两个byte存储
            for(int dataIndex=0;dataIndex<rawDataSize;dataIndex++)
            {
                int dateTemp=Integer.parseInt(currentDateTimeSplit[dataIndex]);
                if(dataIndex==0)
                {
                    byte H8bits=(byte)((dateTemp)>>8);
                    byte L8bits=(byte)((dateTemp)&0xff);
                    dateTimeBytes[dataIndex]= H8bits;
                    dateTimeBytes[dataIndex+1]= L8bits;
                }
                dateTimeBytes[dataIndex+1]=(byte)dateTemp;
            }
        }else
        {
            System.out.println("当前时间获取出现异常数据");
            System.exit(-1);
            dateTimeBytes=null;
        }
        return dateTimeBytes;
    }
    
    /*
     * 将数组封装成帧
     * 每一个数据帧由以下几个部分组成
     * 1)数据包头部 head 0X2F
     * 2)数据包命令 CMD  0X5A
     * 3)数据个数     length of data 7
     * 4)校验和         H8/L8 byte of  check sum(高字节在前 低字节在后)
     * 5)数据结尾标志 tail OX30
     * 6)可采用线程进行获取当前时间
     */
     public static byte[] makeCurrentDateTimefromStringtoFramePackage(byte[] dateTimeBytes)
     {
         //在时间byte[]前后添加一些package校验信息
         int dataLength=13;
         byte[] terimalTimePackage=new byte[dataLength];
         //装填信息
         //时间数据包之前的信息
         terimalTimePackage[0]=0x2F;
         terimalTimePackage[1]=0X5A;
         terimalTimePackage[2]=7;
         //计算校验和
         //转化为无符号进行校验
         for(int dataIndex=0;dataIndex<dateTimeBytes.length;dataIndex++)
         {
             terimalTimePackage[dataIndex+3]=dateTimeBytes[dataIndex];
         }
         //将校验和分为高低字节
         byte sumH8bits=(byte)((timeCheckSum)>>8);
         byte sumL8bits=(byte)((timeCheckSum)&0xff);
         terimalTimePackage[10]=sumH8bits;//高字节在前
         terimalTimePackage[11]=sumL8bits;//低字节在后
         //数据包结尾
         terimalTimePackage[12]=0X30;
         return terimalTimePackage;
     }
     
     /*
      * 对时间格式进行解析并还原原来的时间格式
      * 对数据进行还原
      * 仅限于debug使用
      */
     public static String dateTimeBytesfromTostring(byte[] currentDateTime)
     {
         String string="";
         if(currentDateTime.length==7)
         {
           string=((currentDateTime[0]<<8)+bytetoUnsigendInt(currentDateTime[1]))+" "+currentDateTime[2]+" "+
           currentDateTime[3]+" "+currentDateTime[4]+" "+currentDateTime[5]+" "+
           currentDateTime[6];
         }

         return string;
     }

     /*
      * 将byte转化为字符串
      * 将有符号byte转化为无符号数字
      * debug使用
      */
     public  static int bytetoUnsigendInt(byte aByte)
     {
         String s=String.valueOf(aByte);
         //System.out.println(s);
         int bytetoUnsigendInt=0;
         for(int i=0;i<s.length();i++)
         {
             if(s.charAt(i)!='0')
             {
                 bytetoUnsigendInt+=1<<(7-i);
             }
         }
         return bytetoUnsigendInt;
     }
    
    public static void main(String[] args) {
    	 //1.定义变量
        CommPortIdentifier com11 = null;//用于记录本地串口
        SerialPort serialCom11 = null;//用于标识打开的串口

        try {
            //2.获取COM11口
            com11 = CommPortIdentifier.getPortIdentifier("COM1");

            //3.打开COM11
            serialCom11 = (SerialPort) com11.open("Com1Writer", 1000);

            //4.往串口写数据（使用串口对应的输出流对象）
            //4.1.获取串口的输出流对象
            OutputStream outputStream = serialCom11.getOutputStream();

            //4.2.通过串口的输出流向串口写数据“Hello World!”：
            //使用输出流往串口写数据的时候必须将数据转换为byte数组格式或int格式，
            //当另一个串口接收到数据之后再根据双方约定的规则，对数据进行解码。
            outputStream.write(new byte[]{'H','e','l','l','o',
                    ' ','W','o','r','l','d','!'});
            outputStream.flush();
            //4.3.关闭输出流
            outputStream.close();

            //5.关闭串口
            serialCom11.close();
        } catch (NoSuchPortException e) {
            //找不到串口的情况下抛出该异常
            e.printStackTrace();
        } catch (PortInUseException e) {
            //如果因为端口被占用而导致打开失败，则抛出该异常
            e.printStackTrace();
        } catch (IOException e) {
            //如果获取输出流失败，则抛出该异常
            e.printStackTrace();
        }
    	
    }
}
